package android.slc.db.service.impl;

import android.slc.commonlibrary.util.compat.SlcCacheUtils;
import android.slc.commonlibrary.util.compat.SlcPathUtils;
import android.slc.db.core.DbLinkedHashMap;
import android.slc.db.entity.IDbEntity;
import android.slc.db.service.DbEntityMapper;

import com.blankj.utilcode.util.CacheDiskUtils;
import com.blankj.utilcode.util.CacheDoubleUtils;
import com.blankj.utilcode.util.CacheMemoryUtils;
import com.blankj.utilcode.util.PathUtils;

import cn.hutool.core.thread.ThreadUtil;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * @author slc
 * @date 2023/04/19 下午 7:07
 */
public class DbEntityMapperImpl<T extends IDbEntity<? extends Serializable>> implements DbEntityMapper<T> {
    private static final String DEF_DB_NAME = "box_entity_db";
    public String dbName;
    public String tableName;
    private final CacheDoubleUtils cacheDoubleUtils;
    private Map<String, T> dataMap;
    private final List<OnDbChangeListener<T>> onDbChangeListenerSet = new ArrayList<>();

    private Iterator<OnDbChangeListener<T>> getDbChangeListenerIterator() {
        synchronized (onDbChangeListenerSet) {
            return onDbChangeListenerSet.iterator();
        }
    }

    public DbEntityMapperImpl(String tableName) {
        this(DEF_DB_NAME, tableName);
    }

    public DbEntityMapperImpl(String dbName, String tableName) {
        this.dbName = dbName;
        this.tableName = tableName;
        this.cacheDoubleUtils = CacheDoubleUtils.getInstance(CacheMemoryUtils.getInstance(dbName, 1024),
                CacheDiskUtils.getInstance(SlcPathUtils.createAppDbFile(dbName)));
    }

    public Map<String, T> getAllPrivate() {
        if(dataMap==null){
            synchronized (this){
                if(dataMap==null){
                    dataMap = new DbLinkedHashMap<>();
                    dataMap.putAll(SlcCacheUtils.getMap(this.cacheDoubleUtils, tableName, getThisEntityClass()));
                }
            }
        }
        return dataMap;
    }

    @Override
    public void synchronousData(Map<String, T> entityMap) {
        SlcCacheUtils.saveData(cacheDoubleUtils, tableName, entityMap);
    }

    /**
     * 通知添加
     *
     * @param list
     */
    @Override
    public void notifyPut(List<T> list) {
        if (list == null || list.isEmpty()) {
            return;
        }
        ThreadUtil.execute(() -> {
            Iterator<OnDbChangeListener<T>> iterator = getDbChangeListenerIterator();
            while (iterator.hasNext()) {
                OnDbChangeListener<T> onDbChangeListener = iterator.next();
                if (onDbChangeListener != null
                        && (onDbChangeListener.getAction().contains(Action.ALL)
                        || onDbChangeListener.getAction().contains(Action.PUT))) {
                    onDbChangeListener.onChange(Action.PUT, list);
                }
            }
        });
    }

    /**
     * 通知更新
     *
     * @param list
     */
    @Override
    public void notifyUpdate(List<T> list) {
        if (list == null || list.isEmpty()) {
            return;
        }
        ThreadUtil.execute(() -> {
            Iterator<OnDbChangeListener<T>> iterator = getDbChangeListenerIterator();
            while (iterator.hasNext()) {
                OnDbChangeListener<T> onDbChangeListener = iterator.next();
                if (onDbChangeListener != null
                        && (onDbChangeListener.getAction().contains(Action.ALL)
                        || onDbChangeListener.getAction().contains(Action.UPDATE))) {
                    onDbChangeListener.onChange(Action.UPDATE, list);
                }
            }
        });
    }

    @Override
    public void notifyRemove(List<T> list) {
        if (list == null || list.isEmpty()) {
            return;
        }
        ThreadUtil.execute(() -> {
            Iterator<OnDbChangeListener<T>> iterator = getDbChangeListenerIterator();
            while (iterator.hasNext()) {
                OnDbChangeListener<T> onDbChangeListener = iterator.next();
                if (onDbChangeListener != null
                        && (onDbChangeListener.getAction().contains(Action.ALL)
                        || onDbChangeListener.getAction().contains(Action.DELETE))) {
                    onDbChangeListener.onChange(Action.DELETE, list);
                }
            }
        });
    }

    @Override
    public void addDbChangeListener(OnDbChangeListener<T> onDbChangeListener) {
        onDbChangeListenerSet.add(onDbChangeListener);
    }

    @Override
    public void removeOnDbChangeListener(OnDbChangeListener<T> onDbChangeListener) {
        onDbChangeListenerSet.remove(onDbChangeListener);
    }
}
